﻿using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Volo.Abp;

namespace Shared.Service.DataScopes.UserPolicyScopes
{
    /// <summary>
    /// 策略定义 用来描述一个策略和那些实体的关系
    /// </summary>

    public class PolicyDefinition
    {
        /// <summary>
        /// 全局策略
        /// </summary>
        private static readonly Dictionary<string, PolicyDefinition> GlobalPolicyDefinitions = new Dictionary<string, PolicyDefinition>();

        /// <summary>
        /// 策略绑定的权限名称
        /// </summary>
        private static readonly string PermissionNamesKey = "PermissionNames";


        /// <summary>
        /// Unique name of the policy.
        /// </summary>
        public string Name { get; }

        /// <summary>
        /// 策略所对应的实体
        /// </summary>
        public List<Type> EntityTypes { get; }

        /// <summary>
        /// 扩展属性
        /// </summary>
        public Dictionary<string, object> Properties { get; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public object this[string name]
        {
            get => Properties.GetOrDefault(name);
            set => Properties[name] = value;
        }

        protected internal PolicyDefinition(
            [NotNull] string name, params Type[] entityTypes)
        {
            Name = Check.NotNull(name, nameof(name));

            Check.NotNull(entityTypes, nameof(entityTypes));

            EntityTypes = new List<Type>();
            Properties = new Dictionary<string, object>();

            EntityTypes.AddRange(entityTypes);
        }

        /// <summary>
        /// Sets a property in the <see cref="Properties"/> dictionary.
        /// This is a shortcut for nested calls on this object.
        /// </summary>
        public virtual PolicyDefinition WithProperty(string key, object value)
        {
            Properties[key] = value;
            return this;
        }


        /// <summary>
        /// 子策略
        /// </summary>
        /// <returns></returns>
        public virtual string[] GetPermissionNames()
        {
            if (Properties.TryGetValue(PermissionNamesKey, out var subPolicies))
            {
                return subPolicies as string[];
            }

            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="permissionNames"></param>
        /// <returns></returns>
        public virtual PolicyDefinition AddPermissionNames(params string[] permissionNames)
        {
            var permissionNameList = (GetPermissionNames() ?? new string[0]).ToList();
            permissionNameList.AddRange(permissionNames);

            return WithProperty(PermissionNamesKey, permissionNameList.ToArray());
        }


        public override string ToString()
        {
            return $"[{nameof(PolicyDefinition)} {Name}]";
        }


        #region 静态方法

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="entityTypes"></param>
        /// <returns></returns>
        public static PolicyDefinition AddPolicyDefinition([NotNull] string name, params Type[] entityTypes)
        {
            return GlobalPolicyDefinitions[name] = new PolicyDefinition(name, entityTypes);
        }
      
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="permissionNames"></param>
        /// <returns></returns>
        public static PolicyDefinition AddPolicyDefinition([NotNull] string name, params string[] permissionNames)
        {
            return GlobalPolicyDefinitions[name] = new PolicyDefinition(name).AddPermissionNames(permissionNames);
        }

        #endregion


        public static PolicyDefinition GetOrDefault(string name)
        {
            return GlobalPolicyDefinitions.GetValueOrDefault(name);
        }
    }
}
